package com.gitee.zzh.codegenerator;

import com.gitee.zzh.common.StrUtil;

import java.util.List;
import java.util.Map;

public class DefaultCustomCodeImpl implements CustomCode {

    private final List<Map<String, String>> tableColumns;
    private final List<String> tablePrimaryKeyList;
    private final String tableName;

    public DefaultCustomCodeImpl(List<Map<String, String>> tableColumns,
                                 List<String> tablePrimaryKeyList,
                                 String tableName) {
        this.tableColumns = tableColumns;
        this.tablePrimaryKeyList = tablePrimaryKeyList;
        this.tableName = tableName;
    }

    @Override
    public String getResultMapList() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String columnType = map.get("TYPE_NAME");
            String jdbcType = StrUtil.getJdbcTypeName(columnType);
            if(tablePrimaryKeyList.contains(columnName)) {
                stringBuilder.append("        <id column=\"").append(columnName).append("\" property=\"").append(fieldName).append("\" jdbcType=\"").append(jdbcType).append("\"/>\n");
            } else {
                stringBuilder.append("        <result column=\"").append(columnName).append("\" property=\"").append(fieldName).append("\" jdbcType=\"").append(jdbcType).append("\"/>\n");
            }
        }
        return stringBuilder.toString();
    }

    public String getColumnListWithAlias(String alias) {
        StringBuilder stringBuilder = new StringBuilder();
        boolean bool = alias != null && !alias.isBlank();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            if(bool) {
                stringBuilder.append(alias).append(".").append(columnName);
            } else {
                stringBuilder.append(columnName);
            }
            stringBuilder.append(",");
        }
        if(!stringBuilder.isEmpty()) {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
        return stringBuilder.toString();
    }

    @Override
    public String getWhereIfList(String alias) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String fieldName = "param." + StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String columnType = map.get("TYPE_NAME");
            String jdbcType=", jdbcType=" + StrUtil.getJdbcTypeName(columnType);
            if (!tablePrimaryKeyList.contains(columnName)) {
                if(alias != null && !alias.isBlank()) {
                    stringBuilder.append("                <if test=\"").append(fieldName).append(" !=null and ")
                            .append(fieldName).append(" !=''\">\n" +
                                    "                    and ").append(alias).append(".").append(columnName).append("=#{").append(fieldName).append(jdbcType)
                            .append("}\n                </if>\n");
                } else {
                    stringBuilder.append("                <if test=\"").append(fieldName).append(" !=null and ")
                            .append(fieldName).append(" !=''\">\n" +
                                    "                    and ").append(columnName).append("=#{").append(fieldName).append(jdbcType)
                            .append("}\n                </if>\n");
                }
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public String getWhereIds() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            if(!tablePrimaryKeyList.contains(columnName)) {
                continue;
            }
            String fieldName = "param." + StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String columnType = map.get("TYPE_NAME");
            String jdbcType=", jdbcType=" + StrUtil.getJdbcTypeName(columnType);
            if(stringBuilder.isEmpty()) {
                stringBuilder.append(columnName).append("=#{").append(fieldName).append(jdbcType).append("}\n");
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public String getInsertValueList() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String columnType = map.get("TYPE_NAME");
            String fieldName = "param." + StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String jdbcType=", jdbcType=" + StrUtil.getJdbcTypeName(columnType);
            stringBuilder.append("#{").append(fieldName).append(jdbcType).append("},");
        }
        if(!stringBuilder.isEmpty()) {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
        return stringBuilder.toString();
    }

    @Override
    public String getSetIfList() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String columnType = map.get("TYPE_NAME");
            String fieldName = "param." + StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String jdbcType=", jdbcType=" + StrUtil.getJdbcTypeName(columnType);
            if (!tablePrimaryKeyList.contains(columnName)) {
                stringBuilder.append("            <if test=\"").append(fieldName).append(" !=null and ").append(fieldName).append(" !=''\">\n                ")
                        .append(columnName).append("=#{").append(fieldName).append(jdbcType)
                        .append("},\n            </if>\n");
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public String getEntityToVOSetterFields() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String columnType = map.get("TYPE_NAME");
            String fieldClassName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(tableName, 4));
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String fieldTypeName = StrUtil.getFieldTypeName(columnType);
            if("Timestamp".equals(fieldTypeName) || "Date".equals(fieldTypeName)) {
                continue;
            }
            String gsField = StrUtil.unlineToPascal(fieldName, 10);
            if("String".equals(fieldTypeName)) {
                stringBuilder.append("        ").append(fieldClassName).append("VO.set")
                        .append(gsField).append("(").append(fieldClassName).append("Entity.get")
                        .append(gsField).append("());\n");
            } else {
                stringBuilder.append("        ").append(fieldClassName).append("VO.set")
                        .append(gsField).append("(String.valueOf(").append(fieldClassName).append("Entity.get")
                        .append(gsField).append("()));\n");
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public String getVOToEntitySetterFields() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String columnType = map.get("TYPE_NAME");
            String fieldClassName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(tableName, 10));
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String fieldTypeName = StrUtil.getFieldTypeName(columnType);
            if("Timestamp".equals(fieldTypeName) || "Date".equals(fieldTypeName)) {
                continue;
            }
            String gsField = StrUtil.unlineToPascal(fieldName, 10);
            if("String".equals(fieldTypeName)) {
                stringBuilder.append("        ").append(fieldClassName).append("Entity.set")
                        .append(gsField).append("(").append(fieldClassName).append("VO.get")
                        .append(gsField).append("());\n");
            } else if("Integer".equals(fieldTypeName)) {
                stringBuilder.append("        String ").append(fieldName).append(" = ").append(fieldClassName).append("VO.get")
                        .append(gsField).append("();\n        if(").append(fieldName).append(" != null) {\n");
                stringBuilder.append("            ").append(fieldClassName).append("Entity.set")
                        .append(gsField).append("(Integer.parseInt(").append(fieldClassName).append("VO.get")
                        .append(gsField).append("()));\n        }\n");
            } else if("BigDecimal".equals(fieldTypeName)) {
                stringBuilder.append("        String ").append(fieldName).append(" = ").append(fieldClassName).append("VO.get")
                        .append(gsField).append("();\n        if(").append(fieldName).append(" != null) {\n");
                stringBuilder.append("            ").append(fieldClassName).append("VO.set")
                        .append(gsField).append("(new BigDecimal(").append(fieldClassName).append("Entity.get")
                        .append(gsField).append("()));\n        }\n");
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public String getFieldEntityList() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String comment = map.get("REMARKS");
            String columnName = map.get("COLUMN_NAME");
            String columnType = map.get("TYPE_NAME");
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String fieldTypeName = StrUtil.getFieldTypeName(columnType);
            stringBuilder.append("    /**\n     *").append(comment == null? "" : comment).append("\n     */\n");
            stringBuilder.append("    private ").append(fieldTypeName).append(" ").append(fieldName).append(";\n\n");
        }

        for (Map<String, String> map : tableColumns) {
            String columnType = map.get("TYPE_NAME");
            String columnName = map.get("COLUMN_NAME");
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            String fieldTypeName = StrUtil.getFieldTypeName(columnType);
            stringBuilder.append("    public ").append(fieldTypeName).append(StrUtil.getMethodName(fieldName, " get")).append("(){\n" +
                    "        return ").append(fieldName).append(";\n    }\n");
            stringBuilder.append("    public void ").append(StrUtil.getMethodName(fieldName, "set")).append("(").append(fieldTypeName).append(" ").append(fieldName).append("){\n" +
                    "        this.").append(fieldName).append(" = ").append(fieldName).append(";\n    }\n");
        }
        return stringBuilder.toString();
    }

    @Override
    public String getFieldVOList() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map<String, String> map : tableColumns) {
            String comment = map.get("REMARKS");
            String columnName = map.get("COLUMN_NAME");
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            stringBuilder.append("    @Schema(description = \"").append(comment).append("\", example = \"\")\n");
            stringBuilder.append("    private ").append("String").append(" ").append(fieldName).append(";\n\n");
        }

        for (Map<String, String> map : tableColumns) {
            String columnName = map.get("COLUMN_NAME");
            String fieldName = StrUtil.firstToLowerCase(StrUtil.unlineToPascal(columnName, 10));
            stringBuilder.append("    public String ").append(StrUtil.getMethodName(fieldName, "get")).append("(){\n" +
                    "        return ").append(fieldName).append(";\n    }\n");
            stringBuilder.append("    public void ").append(StrUtil.getMethodName(fieldName, "set")).append("(String ").append(fieldName).append("){\n" +
                    "        this.").append(fieldName).append(" = ").append(fieldName).append(";\n" +
                    "    }\n");
        }
        return stringBuilder.toString();
    }
}
